﻿using IOC.Annotation;
using ORM.Base;
using ORM.DB;
using ORM.Model;
using ORM.Util;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ORM.Applicaiton
{
    [Component]
    public class DBUtil
    {
        private string ConnectStringName = "Base_ConnectionString";
        private PreCommand command = null;
        private bool tracesql;
        public string GlobalTransitionID { set; get; }
        public bool TraceSQL
        {
            get { return tracesql; }

            set
            {
                tracesql = value;
                command.TraceSQL = value;
            }
        }

        public DBUtil()
        {
            command = new PreCommand();

        }

        public DBUtil(string ConnectStringName)
        {
            command = new PreCommand();
            this.ConnectStringName = ConnectStringName;
        }

        public static void Init()
        {
            MapperBuilder.GetInstance();
        }

        public void Insert<T>(T Entity) where T : BaseEntity
        {
            Command cmd = command.InitInsert(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Insert<T>(T Entity, string ConnectStringName) where T : BaseEntity
        {
            Command cmd = command.InitInsert(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Remove<T>(T Entity) where T : BaseEntity
        {
            Command cmd = command.InitRemove<T>(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Remove<T>(T Entity, string ConnectStringName) where T : BaseEntity
        {
            Command cmd = command.InitRemove(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Save<T>(T Entity) where T : BaseEntity
        {
            Command cmd = command.InitSave<T>(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Save<T>(T Entity, string ConnectStringName) where T : BaseEntity
        {
            Command cmd = command.InitSave<T>(Entity, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }


        public void Save<T>(T Entity, string[] SaveColumn) where T : BaseEntity
        {
            Command cmd = null;
            cmd = command.InitSave<T>(Entity, SaveColumn, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void Save<T>(T Entity, string[] SaveColumn, string ConnectStringName) where T : BaseEntity
        {
            Command cmd = null;
            cmd = command.InitSave<T>(Entity, SaveColumn, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public int Count<T>() where T : BaseEntity
        {
            Command cmd = command.InitCount<T>(ConnectStringName);
            return Convert.ToInt32(cmd.ExecuteForResult());
        }

        public int Count<T>(string ConnectStringName) where T : BaseEntity
        {
            Command cmd = command.InitCount<T>(ConnectStringName);
            return Convert.ToInt32(cmd.ExecuteForResult());
        }

        public void InsertBatch<T>(List<T> EntityList, int BatchSize = 500) where T : BaseEntity
        {
            command.InsertBatch<T>(EntityList, ConnectStringName, BatchSize);
        }

        public void InsertBatch<T>(List<T> EntityList, string ConnectStringName, int BatchSize = 500) where T : BaseEntity
        {
            command.InsertBatch<T>(EntityList, ConnectStringName, BatchSize);
        }

        public List<T> FindList<T>(string SQL) where T : BaseEntity
        {
            List<T> result = command.InitFindList<T>(SQL, ConnectStringName).Query<T>();
            return result;
        }

        public List<T> FindList<T>(string SQL, string ConnectStringName) where T : BaseEntity
        {
            List<T> result = command.InitFindList<T>(SQL, ConnectStringName).Query<T>();
            return result;
        }

        public DataTable FindView(string SQL)
        {
            DataTable result = command.InitFindView(SQL, ConnectStringName).QueryView();
            return result;
        }

        public DataTable FindView(string SQL, string ConnectStringName)
        {
            DataTable result = command.InitFindView(SQL, ConnectStringName).QueryView();
            return result;
        }

        public T FindOne<T>(string KeyGuid) where T : BaseEntity
        {
            T result = command.InitFindOne<T>(KeyGuid, ConnectStringName).Query<T>()[0];
            return result;
        }

        public T FindOne<T>(string KeyGuid, string ConnectStringName) where T : BaseEntity
        {
            T result = command.InitFindOne<T>(KeyGuid, ConnectStringName).Query<T>()[0];
            return result;
        }

        public List<T> FindListPage<T>(string SQL, int PageSize, int PageNum, string OrderBy) where T : BaseEntity
        {
            List<T> result = command.InitFindPage<T>(SQL, PageSize, PageNum, OrderBy, ConnectStringName).Query<T>();
            return result;
        }

        public List<T> FindListPage<T>(string SQL, int PageSize, int PageNum, string OrderBy, string ConnectStringName) where T : BaseEntity
        {
            List<T> result = command.InitFindPage<T>(SQL, PageSize, PageNum, OrderBy, ConnectStringName).Query<T>();
            return result;
        }

        public DataTable FindViewPage<T>(string SQL, int PageSize, int PageNum, string OrderBy)
        {
            DataTable result = command.InitFindViewPage(SQL, PageSize, PageNum, OrderBy, ConnectStringName).QueryView();
            return result;
        }

        public DataTable FindViewPage<T>(string SQL, int PageSize, int PageNum, string OrderBy, string ConnectStringName)
        {
            DataTable result = command.InitFindViewPage(SQL, PageSize, PageNum, OrderBy, ConnectStringName).QueryView();
            return result;
        }

        public void ExecuteSQL(string SQL)
        {
            Command cmd = command.InitExecuteSQL(SQL, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public void ExecuteSQL(string SQL, string ConnectStringName)
        {
            Command cmd = command.InitExecuteSQL(SQL, ConnectStringName);
            if (null != GlobalTransitionID)
            {
                cmd.GlobalTransitionID = GlobalTransitionID;
            }
            cmd.Execute();
        }

        public Object ExecuteScar(string SQL)
        {
            Command cmd = command.InitExecuteSQL(SQL, ConnectStringName);
            return cmd.ExecuteForResult();
        }

        public Object ExecuteScar(string SQL, string ConnectStringName)
        {
            Command cmd = command.InitExecuteSQL(SQL, ConnectStringName);
            return cmd.ExecuteForResult();
        }

        public bool ExecuteTransition_SDB(Action TransitionAction, out string ExceptionStr)
        {
            bool IsSuccess = true;
            ExceptionStr = string.Empty;
            string MainTaskID = Thread.CurrentThread.ManagedThreadId.ToString();
            var TrabsitionTask = new Task<LocalTransactionResult>(() =>
            {
                string TransitionTaskID = Thread.CurrentThread.ManagedThreadId.ToString();
                LocalTransactionResult Result = new LocalTransactionResult();
                DBHelper _DBHelper = new DBHelper(ConnectStringName);
                using (DbConnection connection = _DBHelper.GetConnection())
                {
                    connection.Open();
                    DbTransaction Transaction = connection.BeginTransaction();
                    LocalTransactionManage.AddTransitionTask(TransitionTaskID, Transaction);
                    try
                    {
                        TransitionAction();
                        Transaction.Commit();
                    }
                    catch (System.Exception e)
                    {
                        Result.ExecuteStatus = false;
                        Result.ExceptionMessage = e.Message;
                        Transaction.Rollback();
                    }
                    finally
                    {
                        Transaction.Dispose();
                        connection.Close();
                        connection.Dispose();
                        Transaction = null;
                        LocalTransactionManage.RemoveTask(TransitionTaskID);
                    }
                    return Result;
                }
            });
            TrabsitionTask.Start();
            TrabsitionTask.Wait();
            IsSuccess = TrabsitionTask.Result.ExecuteStatus;
            ExceptionStr = TrabsitionTask.Result.ExceptionMessage;
            return IsSuccess;

        }

        public bool ExecuteTransition_SDB(Action TransitionAction, string ConnectStringName, out string ExceptionStr)
        {
            bool IsSuccess = true;
            ExceptionStr = string.Empty;
            string MainTaskID = Thread.CurrentThread.ManagedThreadId.ToString();
            var TrabsitionTask = new Task<LocalTransactionResult>(() =>
            {
                string TransitionTaskID = Thread.CurrentThread.ManagedThreadId.ToString();
                LocalTransactionResult Result = new LocalTransactionResult();
                DBHelper _DBHelper = new DBHelper(ConnectStringName);
                using (DbConnection connection = _DBHelper.GetConnection())
                {
                    connection.Open();
                    DbTransaction Transaction = connection.BeginTransaction();
                    LocalTransactionManage.AddTransitionTask(TransitionTaskID, Transaction);
                    try
                    {
                        TransitionAction();
                        Transaction.Commit();
                    }
                    catch (System.Exception e)
                    {
                        Result.ExecuteStatus = false;
                        Result.ExceptionMessage = e.Message;
                        Transaction.Rollback();
                    }
                    finally
                    {
                        Transaction.Dispose();
                        connection.Close();
                        connection.Dispose();
                        Transaction = null;
                        LocalTransactionManage.RemoveTask(TransitionTaskID);
                    }
                    return Result;
                }
            });
            TrabsitionTask.Start();
            TrabsitionTask.Wait();
            IsSuccess = TrabsitionTask.Result.ExecuteStatus;
            ExceptionStr = TrabsitionTask.Result.ExceptionMessage;
            return IsSuccess;

        }

        public bool ExecuteTransition_DDB_HandleRollBack(Action TransitionAction, Action CancelTransitionAction, out string ExceptionStr)
        {
            bool IsSuccess = true;
            ExceptionStr = string.Empty;
            try
            {
                TransitionAction();
            }
            catch (System.Exception e)
            {

                IsSuccess = false;
                ExceptionStr = e.Message + e.StackTrace;
                CancelTransitionAction();
            }
            return IsSuccess;

        }

        public bool ExecuteTransition_DDB_AutoRollBack(Action TransitionAction, out string ExceptionStr)
        {
            bool IsSuccess = true;
            ExceptionStr = string.Empty;
            GlobalTransitionID = ConfigUtil.GetUUID();
            try
            {
                TransitionAction();
            }
            catch (System.Exception e)
            {
                bool IsRollBackSuccess = GlobalTransitionBuilder.GetInstance().ExecuteRollBack(GlobalTransitionID);
                IsSuccess = false;
                ExceptionStr = e.Message + e.StackTrace;
            }
            if (IsSuccess)
            {
                GlobalTransitionBuilder.GetInstance().UpdateBranchStatus(GlobalTransitionID, Enum.UndoStatus.NotNeedUndo);
            }
            GlobalTransitionID = null;
            return IsSuccess;

        }


    }
}
